package sample.classremaper;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.ClassRemapper;
import org.objectweb.asm.commons.SimpleRemapper;
import util.CustomClassLoader;
import util.FileUtils;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * obfuscate
 */
public class ClassRenameDemo {
    public static void main(String[] args) throws IOException {
        Class<?> clazz = HelloWorld.class;
        String originName = Type.getInternalName(clazz);
        String newName = originName + "ClassRename";
        Map<String, String> map = new HashMap<>();
        map.put(originName, newName);
        map.put(originName + ".intValue", "newFieldName");
        map.put(originName + ".test()V", "newMethodName");
        byte[] bytes = invoke(clazz, map);
        //  output
        FileUtils.writeBytes(originName + "ClassRename.class", bytes);

        try {
            CustomClassLoader classLoader = new CustomClassLoader();
            Class clazz1 = classLoader.defineClass("sample.classremaper.HelloWorldClassRename", bytes);
            Object instance = classLoader.invokeInstance(clazz1, new Class[]{}, new Object[]{});
            classLoader.invokeMethod(clazz1, instance, new Class[]{}, "newMethodName", new Object[]{});
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private static byte[] invoke(Class<?> clazz, Map<String, String> map) throws IOException {
        ClassReader classReader = new ClassReader(clazz.getName());
        ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES);


        SimpleRemapper simpleRemapper = new SimpleRemapper(map);
        ClassRemapper visitor = new ClassRemapper(classWriter, simpleRemapper);
        classReader.accept(visitor, ClassReader.EXPAND_FRAMES);
        return classWriter.toByteArray();
    }

}
